package com.generator.code.service;

import com.generator.code.constants.Constant;
import com.generator.code.model.GenColumnEntity;
import com.generator.code.model.GenTableEntity;
import com.generator.code.model.ZipModel;
import com.generator.code.util.ColumnToJavaUtils;
import com.generator.code.util.DateUtils;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;

import java.io.StringWriter;
import java.util.*;

/**
 * @author guoq.z
 * @date 2021/4/1
 */
@Service
public class MySqlGeneratorService {

    /**
     * 所有模板
     *
     * @return 所有模板
     */
    public static List<String> getTemplates() {
        List<String> templates = new ArrayList<String>();
        templates.add("template/Entity.java.vm");
        templates.add("template/Mapper.java.vm");
        templates.add("template/Mapper.xml.vm");
        templates.add("template/Service.java.vm");
        templates.add("template/ServiceImpl.java.vm");
        return templates;
    }

    public List<ZipModel> generatorCode(GenTableEntity table, List<GenColumnEntity> columnsModelList) {
        // 配置信息
        Configuration config = getConfiguration();
        // table
        handlerTable(table, config);
        // columns
        Boolean hasBigDecimal = handlerColumn(table, columnsModelList, config);
        // 生成文件
        return handlerTemplateFile(table, config, hasBigDecimal);
    }

    /**
     * 处理表
     *
     * @param table  表信息
     * @param config generator.properties 配置信息
     */
    public void handlerTable(GenTableEntity table, Configuration config) {
        String tablePrefix = config.getString("tablePrefix");

        //表名转换成Java类名
        String noPrefixTableName = table.getTableName().replaceFirst(tablePrefix, "");
        table.setClassUpperName(ColumnToJavaUtils.convertFirUpper(noPrefixTableName));
        table.setClassLowerName(ColumnToJavaUtils.convertFirUpper(noPrefixTableName));
    }

    /**
     * 获取配置
     *
     * @return 返回配置
     */
    public Configuration getConfiguration() {
        try {
            return new PropertiesConfiguration("generator.properties");
        } catch (Exception ex) {
            throw new RuntimeException("获取配置文件失败", ex);
        }
    }

    /**
     * 处理列
     *
     * @param table            表信息
     * @param columnsModelList 列信息
     * @param config           配置信息
     * @return 列
     */
    public Boolean handlerColumn(GenTableEntity table, List<GenColumnEntity> columnsModelList, Configuration config) {
        boolean hasBigDecimal = false;
        for (GenColumnEntity genColumnEntity : columnsModelList) {
            //列名转换成Java属性名
            genColumnEntity.setAttrLowerName(ColumnToJavaUtils.convertFirLower(genColumnEntity.getColumnName()));
            //列的数据类型，转换成Java类型
            String attrType = config.getString(genColumnEntity.getDataType(), "unKnowType");
            genColumnEntity.setAttrType(attrType);
            if (StringUtils.equalsIgnoreCase(Constant.BigDecimal, attrType)) {
                hasBigDecimal = true;
            }
        }
        table.setColumns(columnsModelList);
        return hasBigDecimal;
    }

    /**
     * 处理模板生成文件
     *
     * @param table         table
     * @param config        config
     * @param hasBigDecimal has
     */
    public List<ZipModel> handlerTemplateFile(GenTableEntity table, Configuration config, Boolean hasBigDecimal) {

        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);

        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("tableName", table.getTableName());
        map.put("comments", table.getComments());
        map.put("className", table.getClassUpperName());
        map.put("classname", table.getClassLowerName());
        map.put("pathName", table.getClassLowerName().toLowerCase());
        map.put("columns", table.getColumns());
        map.put("hasBigDecimal", hasBigDecimal);
        map.put("package", config.getString("package"));
        map.put("author", config.getString("author"));
        map.put("email", config.getString("email"));
        map.put("datetime", DateUtils.nowTime());
        VelocityContext context = new VelocityContext(map);

        //获取模板列表
        List<String> templates = getTemplates();

        List<ZipModel> zipModelList = new ArrayList<>();

        ZipModel zipModel;
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);

            String fileName = getFileName(template, table.getClassUpperName());

            zipModel = new ZipModel();
            zipModel.setFileName(fileName);
            zipModel.setContent(sw.toString());

            zipModelList.add(zipModel);
        }
        return zipModelList;

    }

    /**
     * 生成文件名称
     *
     * @param template  模板名称
     * @param className 表名称
     * @return 文件名
     */
    public String getFileName(String template, String className) {

        if (template.contains(Constant.ENTITY)) {
            return "Entity/" + className + "Entity.java";
        }

        if (template.contains(Constant.SERVICE)) {
            return "IService/" + "I" + className + "Service.java";
        }

        if (template.contains(Constant.IMPL)) {
            return "Impl/" + className + "ServiceImpl.java";
        }

        if (template.contains(Constant.MAPPER)) {
            return "Mapper/" + className + "Mapper.java";
        }

        if (template.contains(Constant.XML)) {
            return "Xml/" + className + "Mapper.xml";
        }

        return null;
    }
}
